import requests
import json
import time
import hashlib
import os
from typing import Optional, Dict


class EnterpriseQQSender:
    """企业QQ消息和文件发送工具"""

    def __init__(self, corpid: str, corpsecret: str, agentid: str):
        """
        初始化企业QQ发送器

        :param corpid: 企业ID，在企业QQ管理后台获取
        :param corpsecret: 应用的凭证密钥
        :param agentid: 应用ID
        """
        self.corpid = corpid
        self.corpsecret = corpsecret
        self.agentid = agentid
        self.access_token = None
        self.token_expires_at = 0

    def _get_access_token(self) -> Optional[str]:
        """获取访问令牌"""
        # 检查token是否有效
        if self.access_token and time.time() < self.token_expires_at - 60:
            return self.access_token

        # 重新获取token
        url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={self.corpid}&corpsecret={self.corpsecret}"

        try:
            response = requests.get(url)
            result = response.json()

            if result.get('errcode') == 0:
                self.access_token = result.get('access_token')
                self.token_expires_at = time.time() + result.get('expires_in', 7200)
                return self.access_token
            else:
                print(f"获取获取access_token失败: {result.get('errmsg')}")
                return None
        except Exception as e:
            print(f"获取access_token时发生错误: {str(e)}")
            return None

    def send_text_message(self, userid: str, content: str) -> Dict:
        """
        发送文本消息

        :param userid: 接收消息的用户ID列表，多个用|分隔
        :param content: 消息内容
        :return: 接口返回结果
        """
        access_token = self._get_access_token()
        if not access_token:
            return {"errcode": -1, "errmsg": "获取access_token失败"}

        url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}"

        data = {
            "touser": userid,
            "msgtype": "text",
            "agentid": self.agentid,
            "text": {
                "content": content
            },
            "safe": 0
        }

        try:
            response = requests.post(url, data=json.dumps(data))
            return response.json()
        except Exception as e:
            print(f"发送文本消息失败: {str(e)}")
            return {"errcode": -1, "errmsg": str(e)}

    def upload_file(self, file_path: str) -> Optional[str]:
        """
        上传文件获取media_id

        :param file_path: 本地文件路径
        :return: 成功返回media_id，失败返回None
        """
        access_token = self._get_access_token()
        if not access_token:
            return None

        if not os.path.exists(file_path):
            print(f"文件不存在: {file_path}")
            return None

        file_size = os.path.getsize(file_path)
        if file_size > 20 * 1024 * 1024:  # 20MB限制
            print("文件大小不能超过20MB")
            return None

        url = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={access_token}&type=file"

        try:
            with open(file_path, 'rb') as f:
                files = {'media': (os.path.basename(file_path), f)}
                response = requests.post(url, files=files)
                result = response.json()

                if result.get('errcode') == 0:
                    return result.get('media_id')
                else:
                    print(f"文件上传失败: {result.get('errmsg')}")
                    return None
        except Exception as e:
            print(f"上传文件时发生错误: {str(e)}")
            return None

    def send_file_message(self, userid: str, media_id: str) -> Dict:
        """
        发送文件消息

        :param userid: 接收消息的用户ID列表，多个用|分隔
        :param media_id: 上传文件返回的media_id
        :return: 接口返回结果
        """
        access_token = self._get_access_token()
        if not access_token:
            return {"errcode": -1, "errmsg": "获取access_token失败"}

        url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}"

        data = {
            "touser": userid,
            "msgtype": "file",
            "agentid": self.agentid,
            "file": {
                "media_id": media_id
            },
            "safe": 0
        }

        try:
            response = requests.post(url, data=json.dumps(data))
            return response.json()
        except Exception as e:
            print(f"发送文件消息失败: {str(e)}")
            return {"errcode": -1, "errmsg": str(e)}


# 使用示例
if __name__ == "__main__":
    # 企业QQ配置信息 - 请替换为实际值
    CORPID = "你的企业ID"
    CORPSECRET = "你的应用密钥"
    AGENTID = "你的应用ID"

    # 初始化发送器
    qq_sender = EnterpriseQQSender(CORPID, CORPSECRET, AGENTID)

    # 接收消息的用户ID
    TO_USER = "user1|user2"  # 多个用户用|分隔，@all表示全体成员

    # 发送文本消息
    print("发送文本消息...")
    text_response = qq_sender.send_text_message(
        userid=TO_USER,
        content="这是一条来自企业QQ API的测试消息"
    )
    print("文本消息发送结果:", text_response)

    # 发送文件
    print("\n发送文件...")
    file_path = "report.xlsx"  # 替换为实际文件路径
    if os.path.exists(file_path):
        media_id = qq_sender.upload_file(file_path)
        if media_id:
            print(f"文件上传成功，media_id: {media_id}")
            file_response = qq_sender.send_file_message(TO_USER, media_id)
            print("文件发送结果:", file_response)
        else:
            print("文件上传失败")
    else:
        print(f"文件不存在: {file_path}")
